﻿using oceanho.webapi.factory.httpAttr;
using oceanho.webapi.factory.httpHandler;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;

namespace oceanho.webapi.factory.httpUtility
{
    /// <summary>
    /// 定义一个工具类。用于解析客户端的请求（包括请求路由映射/调用的义务方法解析）
    /// </summary>
    internal sealed class ReqResolverUtility
    {
        /// <summary>
        /// 解析请求，将请求解析为一个调用的MethodInfo，如果解析失败，或者没有找到对于的方法，返回null
        /// </summary>
        /// <param name="handlerType">httpHander类型</param>
        /// <param name="request">HttpRequest请求对象</param>
        /// <returns></returns>
        public static MethodInfo ResolveReq(Type handlerType, HttpRequest request)
        {
            if (!handlerType.IsSubclassOf(typeof(http_service_handler)))
            {
                throw new TargetException("handlerType must be IsSubclassOf the oceanho.webapi.factory.httpHander.http_service_handler");
            }

            string _reqName = request.PathInfo;
            if (string.IsNullOrEmpty(_reqName))
            {
                return null;
            };

            MethodInfo method = null;                           // 成功解析的方法MethodInfo对象            
            object[] objAttributes = null;                      // 当前（下面的 for）方法的自定义标记属性
            RouterAttribute routerAttr = null;              // 路由解析标记属性对象
            _reqName = _reqName.TrimStart('/').TrimEnd('/');    // 获取请求路径,作为路由解析,请求方法名称解析的依据
            //------------------------------------------------------------------------------------------------//

            // update by oceanho @ 2015-09-05 12:32:05，只检索public的方法 delete as -> | BindingFlags.NonPublic 
            MethodInfo[] methods = handlerType.GetMethods(
                BindingFlags.Instance | BindingFlags.Public);

            for (int i = 0; i < methods.Length; i++)
            {
                if (_reqName.Equals(methods[i].Name,
                    StringComparison.OrdinalIgnoreCase) || (
                    objAttributes = methods[i].GetCustomAttributes(typeof(RouterAttribute), true)).Length > 0)
                {
                    if (objAttributes != null && objAttributes.Length > 0)
                    {
                        routerAttr = (RouterAttribute)objAttributes[0];
                        if (routerAttr.Route != null &&
                            routerAttr.Route.Equals(_reqName, StringComparison.OrdinalIgnoreCase))
                        {
                            method = methods[i];
                            break;
                        }
                    }
                    else { method = methods[i]; break; }
                }
            }

            // 禁止以下几种类型方法代码调用【抽象/不允许调用（有 UnAllowMethodAttribute 标记）】的方法执行
            if (method == null || method.IsAbstract ||
                method.GetCustomAttributes(typeof(UnAllowCallMethodAttribute), false).Length > 0)
            {
                method = null;
            }

            return method;
        }

        #region <--> 辅助方法 <-->


        /// <summary>
        /// 获取HttpRequest的Params参数中,以为prefix为准，最大的值索引值。没有对于prefix的键，返回-1
        /// </summary>
        /// <param name="request">HttpRequest对象</param>
        /// <param name="prefix">参数前缀(或参数名称),比如users[0].hobies[0]=running</param>
        /// <returns></returns>
        internal static int GetReqMaxIndexVal(HttpRequest request, string prefix)
        {
            Match match = null;
            string strT = string.Empty;
            string[] srcKeys = request.Params.AllKeys.Where(
                p => p.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)).ToArray();

            List<string> groupKeys = new List<string>();
            foreach (string key in srcKeys)
            {
                if (((match = Regex.Match(ReplaceDo(key, prefix.Length),
                    ReplaceDo(prefix, prefix.Length) + "[[]\\d+[]]")) != null) && match.Success)
                {
                    groupKeys.Add(match.Value);
                }

                //if (((match = Regex.Match(ReplaceDo(key, prefix.Length),
                //    ReplaceDo(prefix, prefix.Length) + "[[]\\d+[]]")) != null) && match.Success)
                //{
                //    strT = string.Empty;
                //    // maxIntT = Convert.ToInt32(match.Value);
                //    for (int i = match.Value.Length - 2; i >= 0; i--)
                //    {
                //        // is '[' -> 91 | ']' -> 93
                //        if (match.Value[i] == 91)
                //        {
                //            break;
                //        }
                //        strT += match.Value[i];
                //    }
                //    try
                //    {
                //        // 参数最多个数转换与限制
                //        maxIntT = Convert.ToInt32(strT);
                //        if (maxIntT > BinderUtility.MAX_REQ_PARAM_VAL)
                //        {
                //            maxInt = BinderUtility.MAX_REQ_PARAM_VAL;
                //            break;
                //        }
                //    }
                //    catch
                //    {
                //        maxInt = -1;
                //        break;
                //    }
                //    maxInt = maxIntT > maxInt ? maxIntT : maxInt;
                //}
            }
            return groupKeys.Distinct().Count() - 1;
            // return (--maxIntT > BinderUtility.MAX_REQ_PARAM_VAL ? BinderUtility.MAX_REQ_PARAM_VAL : maxIntT);
        }

        /// <summary>
        /// 对请求参数字符串进行调整
        /// </summary>
        /// <param name="refString">需进行截取处理的字符串</param>
        /// <param name="substrLength">截取的长度值</param>
        /// <returns></returns>
        private static string ReplaceDo(string refString, int substrLength)
        {
            string str = refString;
            if (str.Length > substrLength)
            {
                refString = str.Substring(0, substrLength);
                refString = refString.Replace("[", "").Replace("]", "");
                str = refString + str.Substring(substrLength);
            }
            return str;
        }
        #endregion
    }
}
